package com.hellobike.haxing.modules.wms.facade.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hellobike.haxing.common.util.DateUtils;
import com.hellobike.haxing.modules.product.entity.Sku;
import com.hellobike.haxing.modules.product.entity.Spu;
import com.hellobike.haxing.modules.product.service.ISkuService;
import com.hellobike.haxing.modules.product.service.ISpuService;
import com.hellobike.haxing.modules.supplier.entity.TSupplierInfo;
import com.hellobike.haxing.modules.supplier.service.ITSupplierInfoService;
import com.hellobike.haxing.modules.wms.constans.WmsConstans;
import com.hellobike.haxing.modules.wms.dto.*;
import com.hellobike.haxing.modules.wms.entity.*;
import com.hellobike.haxing.modules.wms.enums.*;
import com.hellobike.haxing.modules.wms.exception.WmsServiceException;
import com.hellobike.haxing.modules.wms.facade.WmsReceiveFacade;
import com.hellobike.haxing.modules.wms.facade.WmsStockFacade;
import com.hellobike.haxing.modules.wms.service.*;
import com.hellobike.haxing.modules.wms.utils.ListUtil;
import com.hellobike.haxing.modules.wms.utils.WmsCodeGeneratorUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Component("wmsReceiveFacade")
public class WmsReceiveFacadeImpl implements WmsReceiveFacade {

    @Autowired
    private IAsnHeaderService asnHeaderService;

    @Autowired
    private IAsnDetailService asnDetailService;

    @Autowired
    private ISkuExtService skuExtService;

    @Autowired
    private IStockTaskService stockTaskService;

    @Autowired
    private IDocPutawayService docPutawayService;

    @Autowired
    private WmsStockFacade wmsStockFacade;

    @Autowired
    private ISkuService skuService;
    @Autowired
    private ISpuService spuService;
    @Autowired
    private ILocationService locationService;
    @Autowired
    private IStockBatchAttService stockBatchAttService;
    @Autowired
    private ITSupplierInfoService supplierInfoService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String addAsnByPms(AsnHeader asnHeader, List<AsnDetail> asnDetailList, Long warehouseId, Integer userId) throws WmsServiceException {
        asnHeader.setAsnType(AsnTypeEnum.PURCHASE.getValue());
        if(asnHeader.getRefOrderId() == null || asnHeader.getRefOrderCode() == null){
            throw new WmsServiceException("请回传PO单号信息");
        }
        AsnHeader old = asnHeaderService.getByRefOrderId(asnHeader.getRefOrderId());
        if(old != null){
            throw new WmsServiceException("该PO已同步");
        }
        return addAsn(asnHeader, asnDetailList, warehouseId, userId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String addAsnByHand(AsnHeader asnHeader, List<AsnDetail> asnDetailList, Long warehouseId, Integer userId) throws WmsServiceException {
        asnHeader.setAsnType(AsnTypeEnum.MANUAL.getValue());
        return addAsn(asnHeader, asnDetailList, warehouseId, userId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String addAsnByReturnExchange(AsnHeader asnHeader, List<AsnDetail> asnDetailList, Long warehouseId, Integer userId) throws WmsServiceException {
        asnHeader.setAsnType(AsnTypeEnum.RETURN_EXCHANGE.getValue());
        return addAsn(asnHeader, asnDetailList, warehouseId, userId);
    }


    private String addAsn(AsnHeader asnHeader, List<AsnDetail> asnDetailList, Long warehouseId, Integer userId) throws WmsServiceException {
        if (null == asnHeader.getSupplierId()) {
            throw new WmsServiceException("asn供应商缺失");
        }
        if (null == warehouseId) {
            throw new WmsServiceException("asn仓库缺失");
        }
        asnHeader.setAsnCode(WmsCodeGeneratorUtil.createAsnCode(warehouseId));
        asnHeader.setWarehouseId(warehouseId);
        asnHeader.setAsnStatus(AsnStatusEnum.INIT.getValue());
        asnHeader.setCreateBy(userId);
        if (!asnHeaderService.save(asnHeader)) {
            throw new WmsServiceException("插入asn头部失败");
        }
        if (ListUtil.isNullOrEmpty(asnDetailList)) {
            throw new WmsServiceException("asn明细缺失");
        }
        for (AsnDetail detail : asnDetailList) {
            if (null == detail.getSkuId()) {
                throw new WmsServiceException("skuId缺失");
            }
            if (null == detail.getPurchaseCount()) {
                throw new WmsServiceException("asn采购数量缺失");
            }
            if (detail.getPurchaseCount().compareTo(BigDecimal.ZERO) <= 0) {
                throw new WmsServiceException("asn采购数量小于0");
            }
            detail.setAsnHeaderId(asnHeader.getId());
            detail.setAsnHeaderCode(asnHeader.getAsnCode());
            detail.setLineStatus(AsnStatusEnum.INIT.getValue());
            detail.setWarehouseId(warehouseId);
            detail.setSupplierId(asnHeader.getSupplierId());
            detail.setCreateBy(userId);
        }
        if (!asnDetailService.saveBatch(asnDetailList)) {
            throw new WmsServiceException("插入asn明细失败");
        }
        return asnHeader.getAsnCode();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void receiveAsn(List<AsnDetail> asnDetailList, Long asnHeaderId, String opName, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(asnDetailList)) {
            throw new WmsServiceException("收货明细缺失");
        }
        AsnHeader asnHeader = asnHeaderService.getById(asnHeaderId);
        if (null == asnHeader) {
            throw new WmsServiceException("asn不存在");
        }
        if (!asnHeader.getAsnStatus().equals(AsnStatusEnum.INIT.getValue())) {
            throw new WmsServiceException("asn状态不是初始化");
        }
        List<AsnDetail> details = asnDetailService.getByHeaderId(asnHeaderId);
        if (ListUtil.isNullOrEmpty(details)) {
            throw new WmsServiceException("asn明细缺失");
        }
        Map<Long, AsnDetail> detailMap = asnDetailList.stream().collect(Collectors.toMap(AsnDetail::getId, d -> d));
        for (AsnDetail detail : details) {
            if (!detail.getLineStatus().equals(AsnStatusEnum.INIT.getValue())) {
                throw new WmsServiceException("asn明细状态不是初始化");
            }
            AsnDetail param = detailMap.get(detail.getId());
            if (null == param) {
                throw new WmsServiceException("收货明细参数缺失");
            }
            detail.setReceivedGoodCount(param.getReceivedGoodCount());
            detail.setReceivedBadCount(param.getReceivedBadCount());
            if (detail.getPurchaseCount().compareTo(param.getReceivedGoodCount().add(param.getReceivedBadCount())) != 0) {
                if (param.getDiffReason() == null) {
                    throw new WmsServiceException("未填写不一致原因");
                }
                detail.setDiffReason(param.getDiffReason());
                detail.setDiffReasonDesc(param.getDiffReasonDesc());
            }
            detail.setLineStatus(AsnStatusEnum.COMPLETED.getValue());
            asnDetailService.updateById(detail);
            if (param.getReceivedGoodCount().compareTo(BigDecimal.ZERO) > 0) {
                generatorPutawayTask(asnHeader, detail, param.getReceivedGoodCount(), 0);
            }
            if (param.getReceivedBadCount().compareTo(BigDecimal.ZERO) > 0) {//坏品暂不上架
//                generatorPutawayTask(asnHeader, detail, param.getReceivedBadCount(), 1);
            }
        }
        asnHeader.setAsnStatus(AsnStatusEnum.COMPLETED.getValue());
        asnHeader.setReceivedTime(new Date());
        asnHeader.setOpName(opName);
        if (!asnHeaderService.updateById(asnHeader)) {
            throw new WmsServiceException("完成asn异常");
        }
    }

    private void generatorPutawayTask(AsnHeader asnHeader, AsnDetail detail, BigDecimal qty, Integer damage) throws WmsServiceException {
        StockTask putawayTask = new StockTask();
        putawayTask.setTaskNo(WmsCodeGeneratorUtil.createTaskCode(asnHeader.getWarehouseId()));
        putawayTask.setTaskType(StockTaskTypeEnum.PA.getValue());
        putawayTask.setTaskStatus(StockTaskStatusEnum.INIT.getValue());
        putawayTask.setSkuId(detail.getSkuId());
        putawayTask.setQty(qty);
        putawayTask.setUnitId(detail.getUnitId());
        putawayTask.setUnitName(detail.getUnitName());
//        putawayTask.setBatchId(WmsConstans.DEF_BATCH_ID);
        putawayTask.setDocId(asnHeader.getId());
        putawayTask.setDocLineId(detail.getId());
        putawayTask.setDocNo(asnHeader.getAsnCode());
        putawayTask.setDocType(DocTypeEnum.ASN.getValue());
        putawayTask.setDamaged(damage);
        putawayTask.setLineStatus(detail.getLineStatus());
        putawayTask.setFmLocId(WmsConstans.DEF_RECEIVED_LOC_ID);
        putawayTask.setPlanLocId(skuExtService.getDefSkuLocId(detail.getSkuId(), asnHeader.getWarehouseId()));
        putawayTask.setWarehouseId(asnHeader.getWarehouseId());
        putawayTask.setFmStockId(WmsConstans.DEF_RECEIVED_STOCK_ID);
        if (!stockTaskService.save(putawayTask)) {
            throw new WmsServiceException("任务生成异常");
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void publishDocPutaway(List<Long> taskIds, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(taskIds)) {
            throw new WmsServiceException("暂无上架任务");
        }
        DocPutaway docPutaway = new DocPutaway();
        String orderCode = WmsCodeGeneratorUtil.createPutawayCode(warehouseId);
        docPutaway.setOrderCode(orderCode);
        docPutaway.setOrderStatus(DocPutawayStatusEnum.PUBLISHED.getValue());
        docPutaway.setPrintFlag(0);
        docPutaway.setWarehouseId(warehouseId);
        if (!docPutawayService.save(docPutaway)) {
            throw new WmsServiceException("发布上架单异常");
        }
        for (Long taskId : taskIds) {
            StockTask task = stockTaskService.getById(taskId);
            if (task == null) {
                throw new WmsServiceException("task不存在");
            }
            if (!StockTaskStatusEnum.INIT.getValue().equals(task.getTaskStatus())) {
                throw new WmsServiceException("任务状态不是初始化");
            }
            task.setTaskStatus(StockTaskStatusEnum.PUBLISHED.getValue());
            task.setDocOperId(docPutaway.getId());
            task.setDocOperNo(docPutaway.getOrderCode());
            if (!stockTaskService.updateById(task)) {
                throw new WmsServiceException("task状态异常");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void confirmPutaway(List<StockTaskDto> taskList, Long docPutawayId, String opName, String note, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(taskList)) {
            throw new WmsServiceException("task参数缺失");
        }
        DocPutaway docPutaway = docPutawayService.getById(docPutawayId);
        if (docPutaway == null) {
            throw new WmsServiceException("上架单不存在");
        }
        if (!DocPutawayStatusEnum.PUBLISHED.getValue().equals(docPutaway.getOrderStatus())) {
            throw new WmsServiceException("上架单状态不是已发布");
        }
        List<StockTask> tasks = stockTaskService.getByDocOperId(docPutawayId);
        tasks.sort(Comparator.comparing(StockTask::getSkuId));
        if (ListUtil.isNullOrEmpty(tasks)) {
            throw new WmsServiceException("上架任务明细未找到");
        }
        Map<Long, StockTaskDto> taskMap = taskList.stream().collect(Collectors.toMap(StockTaskDto::getId, v -> v));
        for (StockTask task : tasks) {
            if (!task.getTaskStatus().equals(StockTaskStatusEnum.PUBLISHED.getValue())) {
                throw new WmsServiceException("task状态不是已发布");
            }
            if (!task.getTaskType().equals(StockTaskTypeEnum.PA.getValue())) {
                throw new WmsServiceException("task类型不是上架");
            }
            StockTaskDto param = taskMap.get(task.getId());
            if (param == null) {
                throw new WmsServiceException("tas参数缺失");
            }
            Date skuProductionDate = param.getSkuProductionDate();
            String date;
            if (skuProductionDate != null) {
                date = DateUtils.formatDate(skuProductionDate, "yyyy-MM-dd");
            }else {
                date = "NONE";
            }
            StockBatchAtt stockBatchAtt = stockBatchAttService.getOrCreateBatch(task.getSkuId(),date,task.getDamaged(),warehouseId);
            BigDecimal actQty = param.getActQty();
            //变更库存
            StockChangeDto stockChangeDto = new StockChangeDto();
            stockChangeDto.setSkuId(task.getSkuId());
            stockChangeDto.setToBatchId(stockBatchAtt.getId());
            stockChangeDto.setQty(actQty);
            stockChangeDto.setToLocId(param.getToLocId());
            stockChangeDto.setWarehouseId(warehouseId);
            stockChangeDto.setIsDamaged(task.getDamaged());
            stockChangeDto.setDocId(task.getDocId());
            stockChangeDto.setDocNo(task.getDocNo());
            stockChangeDto.setDocLineId(task.getDocLineId());
            stockChangeDto.setUserId(userId);
            StockChangeDto changeDto = wmsStockFacade.addMainStock(stockChangeDto);
            //更新任务
            task.setToLocId(param.getToLocId());
            task.setToStockId(changeDto.getToStockId());
            task.setActQty(actQty);
            task.setReasonDesc(param.getReasonDesc());
            task.setBatchId(stockBatchAtt.getId());
            task.setTaskStatus(StockTaskStatusEnum.COMPLETED.getValue());
            if (!stockTaskService.updateById(task)) {
                throw new WmsServiceException("更新任务信息异常");
            }
            SkuExt skuExt = skuExtService.getBySkuId(task.getSkuId(), warehouseId);
            if(null == skuExt){
                skuExt = new SkuExt();
                skuExt.setWarehouseId(warehouseId);
                skuExt.setSkuId(task.getSkuId());
                skuExt.setLocId(param.getToLocId());
                skuExtService.save(skuExt);
            }else {
                if(!skuExt.getLocId().equals(param.getToLocId())){
                    skuExt.setLocId(param.getToLocId());
                    skuExtService.updateById(skuExt);
                }
            }
        }
        docPutaway.setNote(note);
        docPutaway.setOpName(opName);
        docPutaway.setOrderStatus(DocPutawayStatusEnum.COMPLETED.getValue());
        if (!docPutawayService.updateById(docPutaway)) {
            throw new WmsServiceException("更新上架单异常");
        }

    }

    @Override
    public AsnHeaderDto queryAsnInfo(Long headerId, Long warehouseId) throws WmsServiceException {
        if (headerId == null) {
            throw new WmsServiceException("参数缺失");
        }
        AsnHeader header = asnHeaderService.getById(headerId);
        if (header == null) {
            throw new WmsServiceException("数据不存在");
        }
        List<AsnDetail> details = asnDetailService.getByHeaderId(headerId);
        if (ListUtil.isNullOrEmpty(details)) {
            throw new WmsServiceException("数据明细不存在");
        }
        AsnHeaderDto asnHeaderDto = new AsnHeaderDto();
        BeanUtils.copyProperties(header,asnHeaderDto);
        TSupplierInfo supplier = supplierInfoService.getById(asnHeaderDto.getSupplierId());
        if (supplier != null) {
            asnHeaderDto.setSupplierName(supplier.getSupplierName());
        }
        for (AsnDetail detail : details) {
            AsnDetailDto detailDto = new AsnDetailDto();
            BeanUtils.copyProperties(detail,detailDto);
            Sku sku = skuService.getById(detail.getSkuId());
            if (sku != null) {
                Spu spu = spuService.getById(sku.getSpuId());
                detailDto.setSpuCode(spu.getSpuCode());
                detailDto.setSpuName(spu.getSpuName());
                detailDto.setSkuCode(sku.getSkuCode());
                detailDto.setBarCode(sku.getBarcode());
                detailDto.setDimensionValues(sku.getDimensionValues());
            }
            asnHeaderDto.getDetailDtoList().add(detailDto);
        }
        return asnHeaderDto;
    }

    @Override
    public List<SkuDto> querySkuByBarCode(String barCode) throws WmsServiceException {
        if (null == barCode || barCode.isEmpty()) {
            throw new WmsServiceException("编码不能为空");
        }
        Sku q = new Sku();
        q.setBarcode(barCode);
        Wrapper<Sku> wrapper = new QueryWrapper<>(q);
        List<Sku> list = skuService.list(wrapper);
        List<SkuDto> rs = new ArrayList<>();
        if(ListUtil.isNotEmpty(list)){
            for (Sku sku : list) {
                Spu spu = spuService.getById(sku.getSpuId());
                SkuDto dto = new SkuDto();
                dto.setSkuId(sku.getId());
                dto.setBarCode(sku.getBarcode());
                dto.setSkuCode(sku.getSkuCode());
                dto.setSpuCode(spu.getSpuCode());
                dto.setSpuName(spu.getSpuName());
                dto.setSkuName(spu.getSpuName());
                dto.setDimensionValues(sku.getDimensionValues());
                rs.add(dto);
            }
        }
        return rs;
    }

    @Override
    public List<StockTaskDto> queryTaskInfoByPutawayId(Long putawayId) throws WmsServiceException {
        if (putawayId == null) {
            throw new WmsServiceException("ID为null");
        }
        List<StockTask> byDocOperId = stockTaskService.getByDocOperId(putawayId);
        List<StockTaskDto> rs = new ArrayList<>();
        if (ListUtil.isNotEmpty(byDocOperId)) {
            wrapperStockTask(byDocOperId, rs);
        }
        return rs;
    }

    private void wrapperStockTask(List<StockTask> list, List<StockTaskDto> rs) {
        for (StockTask stockTask : list) {
            StockTaskDto dto = new StockTaskDto();
            BeanUtils.copyProperties(stockTask,dto);
            Sku sku = skuService.getById(stockTask.getSkuId());
            if(null != sku){
                Spu spu = spuService.getById(sku.getSpuId());
                dto.setBarCode(sku.getBarcode());
                dto.setSkuCode(sku.getSkuCode());
                dto.setSpuCode(spu.getSpuCode());
                dto.setSpuName(spu.getSpuName());
                dto.setDimensionValues(sku.getDimensionValues());
            }
            if (stockTask.getFmLocId() != null) {
                Location location = locationService.getById(stockTask.getFmLocId());
                if (location != null) {
                    dto.setFmLocCode(location.getLocCode());
                }
            }
            if (stockTask.getPlanLocId() != null) {
                Location location = locationService.getById(stockTask.getPlanLocId());
                if (location != null) {
                    dto.setPlanLocCode(location.getLocCode());
                }
            }
            if(stockTask.getToLocId() != null){
                Location location = locationService.getById(stockTask.getToLocId());
                if (location != null) {
                    dto.setToLocCode(location.getLocCode());
                }
            }
            rs.add(dto);
        }
    }

    @Override
    public IPage<StockTaskDto> wrapperStockTaskInfo(IPage<StockTask> pageList) {
        IPage<StockTaskDto> result = new Page<>();
        result.setCurrent(pageList.getCurrent());
        result.setPages(pageList.getPages());
        result.setSize(pageList.getSize());
        result.setTotal(pageList.getTotal());
        List<StockTaskDto> rs = new ArrayList<>();
        if (ListUtil.isNotEmpty(pageList.getRecords())) {
            wrapperStockTask(pageList.getRecords(),rs);
        }
        result.setRecords(rs);
        return result;
    }
}
